import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;

public class Server {
    public static void main(String[] args) throws Exception {
        // 创建UDP协议的Socket套接字用于接收和发送分组
        DatagramSocket serverSocket = new DatagramSocket(8888);
        // 记录最后正确接收到的分组序号
        int endReceive = -1;
        while (true) {
            byte[] data = new byte[100];
            DatagramPacket receivePacket = new DatagramPacket(data, data.length);
            // 服务端接收分组
            serverSocket.receive(receivePacket);
            // 获得分组的序号
            int seq = new String(receivePacket.getData()).charAt(0) - '0';
            // 设置模拟丢包率为0.3（即使收到分组也不返回任何ACK应答）
            if (Math.random() <= 0.7) {
                // 接收到顺序分组
                if (seq == endReceive + 1) {
                    // 封装ack分组
                    byte[] ackData = new String("ack" + seq).getBytes(StandardCharsets.UTF_8);
                    // 获得客户端IP地址
                    InetAddress clientAddress = receivePacket.getAddress();
                    // 获得客户端端口号
                    int clientPort = receivePacket.getPort();
                    DatagramPacket sendPacket = new DatagramPacket(ackData, ackData.length, clientAddress, clientPort);
                    serverSocket.send(sendPacket);
                    // 维护最后正确接收到的分组序号
                    endReceive++;
                    System.out.println("服务端发送 ack=" + seq);
                } else if (endReceive != -1) { // 接收到失序分组
                    // 封装ack分组
                    byte[] ackData = new String("ack" + endReceive).getBytes(StandardCharsets.UTF_8);
                    // 获得客户端IP地址
                    InetAddress clientAddress = receivePacket.getAddress();
                    // 获得客户端端口号
                    int clientPort = receivePacket.getPort();
                    DatagramPacket sendPacket = new DatagramPacket(ackData, ackData.length, clientAddress, clientPort);
                    serverSocket.send(sendPacket);
                    System.out.println("服务端发送 ack=" + endReceive);
                }
            }
        }
    }
}
